package com.fa4j.product.item.service.impl;

import com.fa4j.common.base.exception.CommonRequestError;
import com.fa4j.common.base.model.CommonState;
import com.fa4j.common.base.model.DiffList;
import com.fa4j.common.base.model.RemoveCmd;
import com.fa4j.common.base.util.DiffListUtil;
import com.fa4j.product.category.model.Category;
import com.fa4j.product.category.model.CategoryAttribute;
import com.fa4j.product.category.repository.CategoryRepository;
import com.fa4j.product.item.convert.ItemConverter;
import com.fa4j.product.item.model.*;
import com.fa4j.product.item.repository.ItemAttrRepository;
import com.fa4j.product.item.repository.ItemRepository;
import com.fa4j.product.item.repository.ItemSpecRepository;
import com.fa4j.product.item.service.ItemService;
import com.fa4j.product.stock.service.StockService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 服务实现-商品信息
 *
 * @since 2025-11-22 21:06:24
 */
@Slf4j
@Service
@Validated
@RequiredArgsConstructor
public class ItemServiceImpl implements ItemService {

    private final ItemRepository itemRepository;
    private final ItemSpecRepository itemSpecRepository;
    private final ItemAttrRepository itemAttrRepository;
    private final CategoryRepository categoryRepository;

    private final ItemConverter itemConverter;

    private final StockService stockService;

    /**
     * 商品信息-创建
     *
     * @param cmd 创建参数
     * @return 商品信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Item create(@Valid ItemCreateCmd cmd) {
        Category category = categoryRepository.findById(cmd.getCategoryId())
                .orElseThrow(() -> CommonRequestError.NOT_FOUND.build("商品分类"));
        if (category.getState() == CommonState.DISABLE) {
            throw CommonRequestError.BAD_REQUEST.build("商品分类" + category.getName() + "不可用");
        }
        validCategoryAttribute(category.getAttrList(), cmd.getAttrList());

        Item entity = itemConverter.toEntity(cmd);
        entity.setState(ItemState.DRAFT);
        itemRepository.create(entity);
        saveAttrList(entity, null, null);
        saveSpecList(entity, null);
        // 创建库存
        stockService.saveStock(itemConverter.toSaveStockCmd(entity));
        return entity;
    }

    /**
     * 校验商品分类属性
     */
    private void validCategoryAttribute(List<CategoryAttribute> cateAttrList, List<ItemCreateCmd.Attr> itemAttrList) {
        for (CategoryAttribute cateAttr : cateAttrList) {
            if (cateAttr.getRequired() != null && cateAttr.getRequired()) {
                if (itemAttrList.stream().noneMatch(attr -> Objects.equals(attr.attrName(), cateAttr.getName()))) {
                    throw CommonRequestError.BAD_REQUEST.build("商品属性" + cateAttr.getName() + "必填");
                }
            }
            if (cateAttr.getMulti() == null || !cateAttr.getMulti()) {
                if (itemAttrList.stream().filter(attr -> Objects.equals(attr.attrName(), cateAttr.getName())).count() > 1) {
                    throw CommonRequestError.BAD_REQUEST.build("商品属性" + cateAttr.getName() + "不支持多个值");
                }
            }
        }
    }

    /**
     * 商品信息-编辑
     *
     * @param cmd 编辑参数
     * @return 商品信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Item modify(@Valid ItemModifyCmd cmd) {
        Item entity = itemRepository.findById(cmd.getId())
                .orElseThrow(() -> CommonRequestError.NOT_FOUND.build("商品信息"));
        if (entity.getState() == ItemState.ON_SALE) {
            throw CommonRequestError.BAD_REQUEST.build("商品已上架，不能被修改");
        }
        List<ItemSpec> existSpecList = entity.getSpecList();
        List<ItemAttr> existAttrList = entity.getAttrList();
        itemConverter.updateEntity(entity, cmd);
        itemRepository.modify(entity);
        saveAttrList(entity, null, existAttrList);
        saveSpecList(entity, existSpecList);
        // 同步库存
        stockService.saveStock(itemConverter.toSaveStockCmd(entity));
        return entity;
    }

    private void saveAttrList(Item entity, ItemSpec spec, List<ItemAttr> existAttrList) {
        DiffList<ItemAttr> diffList = DiffListUtil.diff(existAttrList, entity.getAttrList(),
                attr -> attr.getAttrName() + ":" + attr.getAttrValue(),
                (exist, obj) -> {
                    if (exist != null) {
                        obj.setId(exist.getId());
                        obj.setCreateTime(exist.getCreateTime());
                    }
                    obj.setItemId(entity.getId());
                    obj.setSpecId(spec.getId());
                    obj.setOperatorId(entity.getOperatorId());
                }
        );
        for (ItemAttr obj : diffList.createList()) {
            itemAttrRepository.create(obj);
        }
        for (ItemAttr obj : diffList.modifyList()) {
            itemAttrRepository.modify(obj);
        }
        for (ItemAttr obj : diffList.removeList()) {
            itemAttrRepository.remove(obj);
        }
    }

    private void saveSpecList(Item entity, List<ItemSpec> existSpecList) {
        DiffList<ItemSpec> diffList = DiffListUtil.diff(existSpecList, entity.getSpecList(),
                spec -> spec.getAttrList().stream().map(attr -> attr.getAttrName() + ":" + attr.getAttrValue()).collect(Collectors.joining(",")),
                (exist, obj) -> {
                    if (exist != null) {
                        obj.setId(exist.getId());
                        obj.setCreateTime(exist.getCreateTime());
                    }
                    obj.setItemId(entity.getId());
                    obj.setOperatorId(entity.getOperatorId());
                    obj.setName(obj.getAttrList().stream().map(ItemAttr::getAttrValue).collect(Collectors.joining(";")));
                }
        );
        for (ItemSpec obj : diffList.createList()) {
            itemSpecRepository.create(obj);
            saveAttrList(entity, obj, null);
        }
        for (ItemSpec obj : diffList.modifyList()) {
            existSpecList.stream().filter(e -> e.getId().equals(obj.getId())).findFirst()
                    .ifPresent(exist -> {
                        itemSpecRepository.modify(obj);
                        saveAttrList(entity, obj, exist.getAttrList());
                    });
        }
        for (ItemSpec obj : diffList.removeList()) {
            itemSpecRepository.remove(obj);
            List<ItemAttr> existAttrList = obj.getAttrList();
            obj.setAttrList(null);
            saveAttrList(entity, obj, existAttrList);
        }
    }

    /**
     * 商品信息-删除
     *
     * @param cmd 删除参数
     * @return 商品信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Item remove(@Valid RemoveCmd<Integer> cmd) {
        Item entity = itemRepository.findById(cmd.getId())
                .orElseThrow(() -> CommonRequestError.NOT_FOUND.build("商品信息"));
        if (entity.getState() != ItemState.DRAFT) {
            throw CommonRequestError.BAD_REQUEST.build("草稿状态的商品才能被修改");
        }
        entity.setOperatorId(cmd.getOperatorId());
        itemRepository.remove(entity);
        for (ItemAttr itemAttr : entity.getAttrList()) {
            itemAttr.setOperatorId(cmd.getOperatorId());
            itemAttrRepository.remove(itemAttr);
        }
        for (ItemSpec spec : entity.getSpecList()) {
            spec.setOperatorId(cmd.getOperatorId());
            itemSpecRepository.remove(spec);
            for (ItemAttr itemAttr : spec.getAttrList()) {
                itemAttr.setOperatorId(cmd.getOperatorId());
                itemAttrRepository.remove(itemAttr);
            }
        }
        return entity;
    }

    /**
     * 商品信息-状态修改
     *
     * @param cmd 参数
     */
    @Override
    public void changeState(@Valid ItemStateChangeCmd cmd) {
        Item entity = itemRepository.findById(cmd.getId())
                .orElseThrow(() -> CommonRequestError.NOT_FOUND.build("商品信息"));
        if (!entity.getState().getNextStates().contains(cmd.getState().getCode())) {
            throw CommonRequestError.BAD_REQUEST.build("商品状态不能从" + entity.getState().getName() + "转为" + cmd.getState().getName());
        }
        entity.setState(cmd.getState());
        entity.setOperatorId(cmd.getOperatorId());
        itemRepository.modify(entity);
    }
}






